import Test.HUnit
import System.Process
import System.Cmd
import System.Exit
import System.IO
import Requests
import Helper
import Services
import Data.List (isInfixOf, isSuffixOf, isPrefixOf)
import System.FilePath ((</>))
import System.Directory (createDirectoryIfMissing, removeDirectoryRecursive)

main = runTestTT suite
suite = TestList $ map labelTest tests

labelTest = \(l, tc) -> TestLabel l (TestCase tc)

runSingleTest name = do
    let suite = TestList $ map labelTest (filter (isInfixOf name . fst) tests)
    runTestTT suite

tests = [ 

 ( "US1 List next actions", do
    actual <- cmdOutput []
    let expected = "1. call John\n\
                   \2. check prices of car insurances on the web\n\
                   \3. wrap the present for Christy\n"
    asrtEqCrossPlat expected actual ),

 ( "US1 no $HOME variable", do
    (_, out, _, _) <- runInteractiveProcess ("."</>"nzb") [] Nothing $ Just []
    actual <- hGetContents out
    let expected = "No $HOME environmental variable set.\n\
                   \Try nzb --help\n"
    asrtEqCrossPlat expected actual ),

 ( "US1 wrong api-key", do
    (_, out, _, _) <- runInteractiveProcess ("."</>"nzb") [] Nothing $ Just [("HOME", "TestData/HomeWithWrongKey")] 
    actual <- hGetContents out
    let expected = "Got nothing in response from nozbe.com.\n\
                   \Please ensure that the api-key is correct.\n"
    asrtEqCrossPlat expected actual ),


 ( "US2 Check an action as done", do 
    actual <- cmdOutput ["check", "1"]
    let expected = "1. check prices of car insurances on the web\n\
                   \2. wrap the present for Christy\n"
    asrtEqCrossPlat expected actual
    key <- api_key
    addAction key "Inbox" "Phone" "call%20John"
    return () ),

 ( "US2 Check - invalid number", do 
    actual <- cmdOutput ["check", "4"]
    asrtEqCrossPlat "invalid action number\n" actual ),


 ( "US3 Add action", do
    actual <- cmdOutput ["add", "format c"]
    let expected = "1. format c\n\
                   \2. call John\n\
                   \3. check prices of car insurances on the web\n\
                   \4. wrap the present for Christy\n"
    asrtEqCrossPlat expected actual
    _ <- cmdOutput $ ["check", "1"]
    return () ),


 -- I did not want to use assertEq inside here, because each time
 -- the constant in Main.hs needed to be changed, I would have
 -- to change it here too. I figured the check for prefix and
 -- suffix is good enough.

 ( "US4 help switch", do
    output <- cmdOutput ["--help"]
    let actual = dos2unix output
    let prefix = "nzb -- command line interface to nozbe.com."
    let suffix = "nzb contexts  prints all existing contexts\n"
    assertBool ("pefix wrong, actual is "++actual) $ isPrefixOf prefix actual
    assertBool ("suffix wrong, actual is "++actual)$ isSuffixOf suffix actual ),


 ( "Defect10 --help doesn't print the help when no default config file", do
    (_, out, _, _) <- runInteractiveProcess "./nzb" ["--help"] Nothing $ Just [("HOME", "..")]
    actual <- hGetContents out
    let prefix = "nzb -- command line interface to nozbe.com."
    assertBool "prefix" $ isPrefixOf prefix actual ),
 
 ( "Defect13 --help doesn't print the help when no HOME variable set", do
    (_, out, _, _) <- runInteractiveProcess "./nzb" ["--help"] Nothing $ Just []
    actual <- hGetContents out
    let prefix = "nzb -- command line interface to nozbe.com."
    assertBool "prefix" $ isPrefixOf prefix actual ),


 ( "US6 list next actions filtered by context", do
    actual <- cmdOutput ["Phone", "Home"]
    let expected = "1. call John\n\
                   \2. wrap the present for Christy\n"
    asrtEqCrossPlat expected actual ),


 ( "US8 check multiple actions", do
    actual <- cmdOutput ["check", "1", "2"]
    let expected = "1. wrap the present for Christy\n"
    asrtEqCrossPlat expected actual
    key <- api_key
    addAction key "Inbox" "Internet" "check%20prices%20of%20car%20insurances%20on%20the%20web"
    addAction key "Inbox" "Phone" "call%20John"
    return ()),


 ( "US12 get api-key from nozbe.com", do

    createDirectoryIfMissing False "fake_home"
    (stdin, stdout, _, _) <- runInteractiveProcess ("."</>"nzb") [] Nothing $ Just [("HOME", "fake_home")]
    let expect expected = do
        actual <- hGetContents stdout
        assertEq expected actual

    nozbeEmail <- readFile "nozbe_email"
    hPutStr stdin nozbeEmail

    --expect "\npassword: "

    hPutStrLn stdin "wrong password"

    --expect "failed to login to nozbe.com\npassword: "
    --expect "\npassword: "

    nozbePassword <- readFile "nozbe_password"
    hPutStr stdin nozbePassword

    expect "nozbe.com email address: \
           \password: failed to login to nozbe.com\n\
           \password: \
           \1. call John\n\
           \2. check prices of car insurances on the web\n\
           \3. wrap the present for Christy\n"

    removeDirectoryRecursive "fake_home"
    return () ),
    

 ( "US14 Add an action to context", do
    actual <- cmdOutput ["Phone", "add", "thank Eva"]
    let expected = "1. thank Eva\n\
                   \2. call John\n"
    asrtEqCrossPlat expected actual
    _ <- cmdOutput ["check", "1"]
    return () ),

 ( "US14 invalid context", do
    actual <- cmdOutput ["Phoen", "add", "thank Eva"]
    let expected = "no such context: Phoen\n"
    asrtEqCrossPlat expected actual ),


 ( "US15 check actions in context", do
    actual <- cmdOutput ["Phone", "Home", "check", "1"]
    let expected = "1. wrap the present for Christy\n"
    asrtEqCrossPlat expected actual 
    _ <- cmdOutput ["Phone", "add", "call John"]
    return () ),

 ( "US16 contexts", do
    actual <- cmdOutput ["contexts"]
    let expected = "1. No context\n2. Errand\n3. Phone\n4. Mail\n5. Home\n\
                   \6. Office\n7. Computer\n8. Internet\n9. Search\n\
                   \10. Finance\n11. Time off, Hobby\n12. Waiting-for\n\
                   \13. Later - maybe\n"
    asrtEqCrossPlat expected actual ) ]

api_key = do config_file_contents <- readFile ("TestData"</>"Home"</>".nzb")
             return (head . words $ config_file_contents)

cmdOutput args = do
     (_, stdout, _, _) <- runInteractiveProcess ("."</>"nzb") args Nothing $ Just [("HOME", "TestData/Home")]
     hGetContents stdout


executeCommand cmd = do
     (_, cmd_stdout, _, _) <- runInteractiveCommand cmd
     hGetContents cmd_stdout

assertEq :: (Eq a, Show a) => a -> a -> Assertion 
assertEq = assertEqual ""

asrtEqCrossPlat :: String -> String -> Assertion 
asrtEqCrossPlat expected = (assertEq expected) . dos2unix
